home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / gimpressionist / ppmtool.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-09-03  |  15.9 KB  |  698 lines

  1. #ifdef HAVE_CONFIG_H
  2. #include "config.h"
  3. #else
  4. #define HAVE_DIRENT_H
  5. #define HAVE_UNISTD_H
  6. #endif
  7. #include <stdio.h>
  8. #ifdef HAVE_UNISTD_H
  9. #include <unistd.h>
  10. #endif
  11. #include <string.h>
  12. #include <stdlib.h>
  13. #include <math.h>
  14. #include "ppmtool.h"
  15. #include "gimpressionist.h"
  16. #include <errno.h>
  17. #include "libgimp/stdplugins-intl.h"
  18.  
  19. int readline(FILE *f, char *buffer, int len)
  20. {
  21. again:
  22.   if(!fgets(buffer, len, f))
  23.     return -1;
  24.   if(*buffer == '#') {
  25.     goto again;
  26.   }
  27.   while(strlen(buffer) && buffer[strlen(buffer)-1] <= ' ')
  28.     buffer[strlen(buffer)-1] = '\0';
  29.   return 0;
  30. }
  31.  
  32. void fatal(char *s)
  33. {
  34.   fprintf(stderr, "%s\n", s);
  35.   exit(1);
  36. }
  37.  
  38. void killppm(struct ppm *p)
  39. {
  40.   free(p->col);
  41.   p->col = NULL;
  42.   p->height = p->width = 0;
  43. }
  44.  
  45.  
  46. void newppm(struct ppm *p, int xs, int ys)
  47. {
  48.   int x;
  49.   guchar bgcol[3] = {0,0,0};
  50.  
  51.   if(xs < 1)
  52.     xs = 1;
  53.   if(ys < 1)
  54.     ys = 1;
  55.  
  56.   p->width = xs;
  57.   p->height = ys;
  58.   p->col = g_malloc(xs * 3 * ys);
  59.   for(x = 0; x < xs * 3 * ys; x += 3) {
  60.     p->col[x+0] = bgcol[0];
  61.     p->col[x+1] = bgcol[1];
  62.     p->col[x+2] = bgcol[2];
  63.   }
  64. }
  65.  
  66. void getrgb(struct ppm *s, float xo, float yo, guchar *d)
  67. {
  68.   float ix, iy;
  69.   int x1, x2, y1, y2;
  70.   float x1y1, x2y1, x1y2, x2y2;
  71.   float r, g, b;
  72.   int bail = 0;
  73.   int rowstride = s->width * 3;
  74.  
  75.   if(xo < 0.0) bail=1;
  76.   else if(xo >= s->width-1) { xo = s->width-1; } /* bail=1; */
  77.   if(yo < 0.0) bail=1;
  78.   else if(yo >= s->height-1) { yo= s->height-1; } /* bail=1; */
  79.  
  80.   if(bail) {
  81.     d[0] = d[1] = d[2] = 0;
  82.     return;
  83.   }
  84.  
  85.   ix = (int)xo;
  86.   iy = (int)yo;
  87.  
  88.   /*
  89.   x1 = wrap(ix, s->width);
  90.   x2 = wrap(ix+1, s->width);
  91.   y1 = wrap(iy, s->height);
  92.   y2 = wrap(iy+1, s->height);
  93.   */
  94.   x1 = ix; x2 = ix + 1;
  95.   y1 = iy; y2 = iy + 1;
  96.  
  97.   /* printf("x1=%d y1=%d x2=%d y2=%d\n",x1,y1,x2,y2); */
  98.  
  99.   x1y1 = (1.0-xo+ix)*(1.0-yo+iy);
  100.   x2y1 = (xo-ix)*(1.0-yo+iy);
  101.   x1y2 = (1.0-xo+ix)*(yo-iy);
  102.   x2y2 = (xo-ix)*(yo-iy);
  103.  
  104.   r = s->col[y1*rowstride + x1*3 + 0] * x1y1;
  105.   g = s->col[y1*rowstride + x1*3 + 1] * x1y1;
  106.   b = s->col[y1*rowstride + x1*3 + 2] * x1y1;
  107.  
  108.   if(x2y1 > 0.0) r += s->col[y1*rowstride + x2*3 + 0] * x2y1;
  109.   if(x2y1 > 0.0) g += s->col[y1*rowstride + x2*3 + 1] * x2y1;
  110.   if(x2y1 > 0.0) b += s->col[y1*rowstride + x2*3 + 2] * x2y1;
  111.  
  112.   if(x1y2 > 0.0) r += s->col[y2*rowstride + x1*3 + 0] * x1y2;
  113.   if(x1y2 > 0.0) g += s->col[y2*rowstride + x1*3 + 1] * x1y2;
  114.   if(x1y2 > 0.0) b += s->col[y2*rowstride + x1*3 + 2] * x1y2;
  115.  
  116.   if(x2y2 > 0.0) r += s->col[y2*rowstride + x2*3 + 0] * x2y2;
  117.   if(x2y2 > 0.0) g += s->col[y2*rowstride + x2*3 + 1] * x2y2;
  118.   if(x2y2 > 0.0) b += s->col[y2*rowstride + x2*3 + 2] * x2y2;
  119.  
  120.   d[0] = r;
  121.   d[1] = g;
  122.   d[2] = b;
  123. }
  124.  
  125.  
  126. void resize(struct ppm *p, int nx, int ny)
  127. {
  128.   int x, y;
  129.   float xs = p->width/(float)nx;
  130.   float ys = p->height/(float)ny;
  131.   struct ppm tmp = {0,0,NULL};
  132.  
  133.   newppm(&tmp, nx, ny);
  134.   for(y = 0; y < ny; y++) {
  135.     guchar *row = tmp.col + y * tmp.width * 3;
  136.     for(x = 0; x < nx; x++) {
  137.       getrgb(p, x*xs, y*ys, &row[x*3]);
  138.     }
  139.   }
  140.   killppm(p);
  141.   p->width = tmp.width;
  142.   p->height = tmp.height;
  143.   p->col = tmp.col;
  144. }
  145.  
  146. void rescale(struct ppm *p, double sc)
  147. {
  148.   resize(p, p->width * sc, p->height * sc);
  149. }
  150.  
  151. void resize_fast(struct ppm *p, int nx, int ny)
  152. {
  153.   int x, y;
  154.   float xs = p->width/(float)nx;
  155.   float ys = p->height/(float)ny;
  156.   struct ppm tmp = {0,0,NULL};
  157.  
  158.   newppm(&tmp, nx, ny);
  159.   for(y = 0; y < ny; y++) {
  160.     for(x = 0; x < nx; x++) {
  161.       int rx = x*xs, ry = y*ys;
  162.       memcpy(&tmp.col[y*tmp.width*3+x*3], &p->col[ry*p->width*3+rx*3], 3);
  163.     }
  164.   }
  165.   killppm(p);
  166.   p->width = tmp.width;
  167.   p->height = tmp.height;
  168.   p->col = tmp.col;
  169. }
  170.  
  171.  
  172. struct _BrushHeader
  173. {
  174.   unsigned int   header_size; /*  header_size = sz_BrushHeader + brush name  */
  175.   unsigned int   version;     /*  brush file version #  */
  176.   unsigned int   width;       /*  width of brush  */
  177.   unsigned int   height;      /*  height of brush  */
  178.   unsigned int   bytes;       /*  depth of brush in bytes--always 1 */
  179.   unsigned int   magic_number;/*  GIMP brush magic number  */
  180.   unsigned int   spacing;     /*  brush spacing  */
  181. };
  182.  
  183. void msb2lsb(unsigned int *i)
  184. {
  185.   guchar *p = (guchar *)i, c;
  186.   c = p[1]; p[1] = p[2]; p[2] = c;
  187.   c = p[0]; p[0] = p[3]; p[3] = c;
  188. }
  189.  
  190. void loadgbr(char *fn, struct ppm *p)
  191. {
  192.   FILE *f;
  193.   struct _BrushHeader hdr;
  194.   guchar *ptr;
  195.   int x, y;
  196.  
  197.   f = fopen(fn, "rb");
  198.   if(!f) {
  199.     ptr = findfile(fn);
  200.     f = fopen(ptr, "rb");
  201.   }
  202.  
  203.   if(p->col) killppm(p);
  204.  
  205.   if(!f) {
  206.     fprintf(stderr, "loadgbr: Unable to open file \"%s\"!\n", fn);
  207.     newppm(p, 10,10);
  208.     return;
  209.   }
  210.  
  211.   fread(&hdr, 1, sizeof(struct _BrushHeader), f);
  212.  
  213.   for(x = 0; x < 7; x++)
  214.     msb2lsb(&((unsigned int *)&hdr)[x]);
  215.  
  216.   newppm(p, hdr.width, hdr.height);
  217.  
  218.   ptr = g_malloc(hdr.width);
  219.   fseek(f, hdr.header_size, SEEK_SET);
  220.   for(y = 0; y < p->height; y++) {
  221.     fread(ptr, p->width, 1, f);
  222.     for(x = 0; x < p->width; x++) {
  223.       int k = y*p->width*3 + x*3;
  224.       p->col[k+0] = p->col[k+1] = p->col[k+2] = ptr[x];
  225.     }
  226.   }
  227.   fclose(f);
  228.   free(ptr);
  229. }
  230.  
  231. void loadppm(char *fn, struct ppm *p)
  232. {
  233.   char line[200];
  234.   int y, pgm = 0;
  235.   FILE *f;
  236.  
  237.   if(!strcmp(&fn[strlen(fn)-4], ".gbr")) {
  238.     loadgbr(fn, p);
  239.     return;
  240.   }
  241.  
  242.   f = fopen(fn, "rb");
  243.   if(!f) f = fopen(findfile(fn), "rb");
  244.  
  245.   if(p->col) killppm(p);
  246.  
  247.   if(!f) {
  248.     fprintf(stderr, "loadppm: Unable to open file \"%s\"!\n", fn);
  249.     newppm(p, 10,10);
  250.     return;
  251.     /* fatal("Aborting!"); */
  252.   }
  253.  
  254.   readline(f, line, 200);
  255.   if(strcmp(line, "P6")) {
  256.     if(strcmp(line, "P5")) {
  257.       fclose(f);
  258.       printf( "loadppm: File \"%s\" not PPM/PGM? (line=\"%s\")%c\n", fn, line, 7);
  259.       newppm(p, 10,10);
  260.       return;
  261.       /* fatal("Aborting!"); */
  262.     }
  263.     pgm = 1;
  264.   }
  265.   readline(f, line, 200);
  266.   p->width = atoi(line);
  267.   p->height = atoi(strchr(line, ' ')+1);
  268.   readline(f, line, 200);
  269.   if(strcmp(line, "255")) {
  270.     printf ("loadppm: File \"%s\" not valid PPM/PGM? (line=\"%s\")%c\n", fn, line, 7);
  271.     newppm(p, 10,10);
  272.     return;
  273.     /* fatal("Aborting!"); */
  274.   }
  275.   p->col = g_malloc(p->height * p->width * 3);
  276.  
  277.   if(!pgm) {
  278.     fread(p->col, p->height * 3 * p->width, 1, f);
  279.   } else {
  280.     guchar *tmpcol = g_malloc(p->width * p->height);
  281.     fread(tmpcol, p->height * p->width, 1, f);
  282.     for(y = 0; y < p->width * p->height * 3; y++) {
  283.       p->col[y] = tmpcol[y/3];
  284.     }
  285.   }
  286.   fclose(f);
  287. }
  288.  
  289. void fill(struct ppm *p, guchar *c)
  290. {
  291.   int x, y;
  292.  
  293.   if((c[0] == c[1]) && (c[0] == c[2])) {
  294.     guchar col = c[0];
  295.     for(y = 0; y < p->height; y++) {
  296.       memset(p->col + y*p->width*3, col, p->width*3);
  297.     }
  298.   } else {
  299.     for(y = 0; y < p->height; y++) {
  300.       guchar *row = p->col + y * p->width * 3;
  301.       for(x = 0; x < p->width; x++) {
  302.     int k = x * 3;
  303.     row[k+0] = c[0];
  304.     row[k+1] = c[1];
  305.     row[k+2] = c[2];
  306.       }
  307.     }
  308.   }
  309. }
  310.  
  311. void copyppm(struct ppm *s, struct ppm *p)
  312. {
  313.   if(p->col)
  314.     killppm(p);
  315.   p->width = s->width;
  316.   p->height = s->height;
  317.   p->col = g_malloc(p->width * 3 * p->height);
  318.   memcpy(p->col, s->col, p->width * 3 * p->height);
  319. }
  320.  
  321. void freerotate(struct ppm *p, double amount)
  322. {
  323.   int x, y;
  324.   double nx, ny;
  325.   double R, a;
  326.   struct ppm tmp = {0,0,NULL};
  327.   double f = amount*G_PI*2/360.0;
  328.   int rowstride = p->width * 3;
  329.  
  330.   a = p->width/(float)p->height;
  331.   R = p->width<p->height?p->width/2:p->height/2;
  332.  
  333.   newppm(&tmp, p->width, p->height);
  334.   for(y = 0; y < p->height; y++) {
  335.     for(x = 0; x < p->width; x++) {
  336.       double r, d;
  337.       nx = fabs(x-p->width/2.0);
  338.       ny = fabs(y-p->height/2.0);
  339.       r = sqrt(nx*nx + ny*ny);
  340.  
  341.       d = atan2((y-p->height/2.0),(x-p->width/2.0));
  342.  
  343.       nx = (p->width/2.0 + cos(d-f) * r);
  344.       ny = (p->height/2.0 + sin(d-f) * r);
  345.       getrgb(p, nx, ny, tmp.col + y*rowstride+x*3);
  346.     }
  347.   }
  348.   killppm(p);
  349.   p->width = tmp.width;
  350.   p->height = tmp.height;
  351.   p->col = tmp.col;
  352. }
  353.  
  354. void crop(struct ppm *p, int lx, int ly, int hx, int hy)
  355. {
  356.   struct ppm tmp = {0,0,NULL};
  357.   int x, y;
  358.   int srowstride = p->width * 3;
  359.   int drowstride;
  360.  
  361.   newppm(&tmp, hx-lx, hy-ly);
  362.   drowstride = tmp.width * 3;
  363.   for(y = ly; y < hy; y++)
  364.     for(x = lx; x < hx; x++)
  365.       memcpy(&tmp.col[(y-ly)*drowstride+(x-lx)*3],
  366.          &p->col[y*srowstride+x*3], 3);
  367.   killppm(p);
  368.   p->col = tmp.col;
  369.   p->width = tmp.width;
  370.   p->height = tmp.height;
  371. }
  372.  
  373. void autocrop(struct ppm *p, int room)
  374. {
  375.   int lx = 0, hx = p->width, ly = 0, hy = p->height;
  376.   int x, y, n = 0;
  377.   guchar tc[3];
  378.   struct ppm tmp = {0,0,NULL};
  379.   int rowstride = p->width * 3;
  380.   int drowstride;
  381.  
  382.   /* upper */
  383.   memcpy(&tc, p->col, 3);
  384.   for(y = 0; y < p->height; y++) {
  385.     n = 0;
  386.     for(x = 0; x < p->width; x++) {
  387.       if(memcmp(&tc, &p->col[y*rowstride+x*3], 3)) { n++; break; }
  388.     }
  389.     if(n) break;
  390.   }
  391.   if(n) ly = y;
  392.   /* printf("ly = %d\n", ly); */
  393.  
  394.   /* lower */
  395.   memcpy(&tc, &p->col[(p->height-1)*rowstride], 3);
  396.   for(y = p->height-1; y >= 0; y--) {
  397.     n = 0;
  398.     for(x = 0; x < p->width; x++) {
  399.       if(memcmp(&tc, &p->col[y*rowstride+x*3], 3)) { n++; break; }
  400.     }
  401.     if(n) break;
  402.   }
  403.   if(n) hy = y+1;
  404.   if(hy >= p->height) hy = p->height - 1;
  405.   /* printf("hy = %d\n", hy); */
  406.  
  407.   /* left */
  408.   memcpy(&tc, &p->col[ly*rowstride], 3);
  409.   for(x = 0; x < p->width; x++) {
  410.     n = 0;
  411.     for(y = ly; y <= hy && y < p->height; y++) {
  412.       if(memcmp(&tc, &p->col[y*rowstride+x*3], 3)) { n++; break; }
  413.     }
  414.     if(n) break;
  415.   }
  416.   if(n) lx = x;
  417.   /* printf("lx = %d\n", lx); */
  418.  
  419.   /* right */
  420.   memcpy(&tc, &p->col[ly*rowstride + (p->width-1)*3], 3);
  421.   for(x = p->width-1; x >= 0; x--) {
  422.     n = 0;
  423.     for(y = ly; y <= hy; y++) {
  424.       if(memcmp(&tc, &p->col[y*rowstride+x*3], 3)) { n++; break; }
  425.     }
  426.     if(n) break;
  427.   }
  428.   if(n) hx = x+1;
  429.   /* printf("hx = %d\n", hx); */
  430.  
  431.   lx -= room; if(lx<0) lx = 0;
  432.   ly -= room; if(ly<0) ly = 0;
  433.   hx += room; if(hx>=p->width) hx = p->width-1;
  434.   hy += room; if(hy>=p->height) hy = p->height-1;
  435.  
  436.   newppm(&tmp, hx-lx, hy-ly);
  437.   drowstride = tmp.width * 3;
  438.   for(y = ly; y < hy; y++)
  439.     for(x = lx; x < hx; x++)
  440.       memcpy(&tmp.col[(y-ly)*drowstride+(x-lx)*3],
  441.          &p->col[y*rowstride+x*3], 3);
  442.   killppm(p);
  443.   p->col = tmp.col;
  444.   p->width = tmp.width;
  445.   p->height = tmp.height;
  446. }
  447.  
  448. void pad(struct ppm *p, int left,int right, int top, int bottom, guchar *bg)
  449. {
  450.   int x, y;
  451.   struct ppm tmp = {0,0,NULL};
  452.  
  453.   newppm(&tmp, p->width+left+right, p->height+top+bottom);
  454.   for(y = 0; y < tmp.height; y++) {
  455.     guchar *row, *srcrow;
  456.     row = tmp.col + y * tmp.width * 3;
  457.     if((y < top) || (y >= tmp.height-bottom)) {
  458.       for(x = 0; x < tmp.width; x++) {
  459.     int k = x * 3;
  460.         row[k+0] = bg[0];
  461.         row[k+1] = bg[1];
  462.         row[k+2] = bg[2];
  463.       }
  464.       continue;
  465.     }
  466.     srcrow = p->col + (y-top) * p->width * 3;
  467.     for(x = 0; x < left; x++) {
  468.       int k = x * 3;
  469.       row[k+0] = bg[0];
  470.       row[k+1] = bg[1];
  471.       row[k+2] = bg[2];
  472.     }
  473.     for(; x < tmp.width-right; x++) {
  474.       int k = y * tmp.width * 3 + x * 3;
  475.       tmp.col[k+0] = srcrow[(x-left)*3+0];
  476.       tmp.col[k+1] = srcrow[(x-left)*3+1];
  477.       tmp.col[k+2] = srcrow[(x-left)*3+2];
  478.     }
  479.     for(; x < tmp.width; x++) {
  480.       int k = x * 3;
  481.       row[k+0] = bg[0];
  482.       row[k+1] = bg[1];
  483.       row[k+2] = bg[2];
  484.     }
  485.   }
  486.   killppm(p);
  487.   p->width = tmp.width;
  488.   p->height = tmp.height;
  489.   p->col = tmp.col;
  490. }
  491.  
  492. void saveppm(struct ppm *p, char *fn)
  493. {
  494.   FILE *f = fopen(fn, "wb");
  495.   if (f != NULL)
  496.     {
  497.       fprintf(f, "P6\n%d %d\n255\n", p->width, p->height);
  498.       fwrite(p->col, p->width * 3 * p->height, 1, f);
  499.       fclose(f);
  500.     }
  501.   else
  502.     g_message (_("GIMPressionist:\nFailed to save PPM file '%s':\n%s"),
  503.            fn, g_strerror (errno));
  504. }
  505.  
  506. void edgepad(struct ppm *p, int left,int right, int top, int bottom)
  507. {
  508.   int x,y;
  509.   struct ppm tmp = {0,0,NULL};
  510.   guchar testcol[3] = {0,255,0};
  511.   int srowstride, drowstride;
  512.  
  513.   newppm(&tmp, p->width+left+right, p->height+top+bottom);
  514.   fill(&tmp, testcol);
  515.  
  516.   srowstride = p->width * 3;
  517.   drowstride = tmp.width * 3;
  518.   
  519.   for(y = 0; y < top; y++) {
  520.     memcpy(&tmp.col[y*drowstride+left*3], p->col, srowstride);
  521.   }
  522.   for(; y-top < p->height; y++) {
  523.     memcpy(&tmp.col[y*drowstride+left*3], p->col + (y-top)*srowstride, srowstride);
  524.   }
  525.   for(; y < tmp.height; y++) {
  526.     memcpy(&tmp.col[y*drowstride+left*3], p->col + (p->height-1)*srowstride, srowstride);
  527.   }
  528.   for(y = 0; y < tmp.height; y++) {
  529.     guchar *col, *tmprow;
  530.  
  531.     tmprow = tmp.col + y*drowstride;
  532.     col = tmp.col + y*drowstride + left*3;
  533.  
  534.     for(x = 0; x < left; x++) {
  535.       memcpy(&tmprow[x*3], col, 3);
  536.     }
  537.     col = tmp.col + y*drowstride + (tmp.width-right-1)*3;
  538.     for(x = 0; x < right; x++) {
  539.       memcpy(&tmprow[(x+tmp.width-right-1)*3], col, 3);
  540.     }
  541.   }
  542.   killppm(p);
  543.   p->width = tmp.width;
  544.   p->height = tmp.height;
  545.   p->col = tmp.col;
  546. }
  547.  
  548. void ppmgamma(struct ppm *p, float e, int r, int g, int b)
  549. {
  550.   int x, l = p->width * 3 * p->height;
  551.   guchar xlat[256], *pix;
  552.   if(e > 0.0) for(x = 0; x < 256; x++) {
  553.     xlat[x] = pow((x/255.0),(1.0/e))*255.0;
  554.   } else if(e < 0.0) for(x = 0; x < 256; x++) {
  555.     xlat[255-x] = pow((x/255.0),(-1.0/e))*255.0;
  556.   } else for(x = 0; x < 256; x++) { xlat[x] = 0; }
  557.  
  558.   pix = p->col;
  559.   if(r) for(x = 0; x < l; x += 3) pix[x] = xlat[pix[x]];
  560.   if(g) for(x = 1; x < l; x += 3) pix[x] = xlat[pix[x]];
  561.   if(b) for(x = 2; x < l; x += 3) pix[x] = xlat[pix[x]];
  562. }
  563.  
  564. void ppmbrightness(struct ppm *p, float e, int r, int g, int b)
  565. {
  566.   int x, l = p->width * 3 * p->height;
  567.   guchar xlat[256], *pix;
  568.   for(x = 0; x < 256; x++) {
  569.     xlat[x] = x*e;
  570.   } 
  571.  
  572.   pix = p->col;
  573.   if(r) for(x = 0; x < l; x += 3) pix[x] = xlat[pix[x]];
  574.   if(g) for(x = 1; x < l; x += 3) pix[x] = xlat[pix[x]];
  575.   if(b) for(x = 2; x < l; x += 3) pix[x] = xlat[pix[x]];
  576. }
  577.  
  578.  
  579. void blur(struct ppm *p, int xrad, int yrad)
  580. {
  581.   int x, y, k;
  582.   int tx, ty;
  583.   struct ppm tmp = {0,0,NULL};
  584.   int r, g, b, n;
  585.   int rowstride = p->width * 3;
  586.  
  587.   newppm(&tmp, p->width, p->height);
  588.   for(y = 0; y < p->height; y++) {
  589.     for(x = 0; x < p->width; x++) {
  590.       r = g = b = n = 0;
  591.       for(ty = y-yrad; ty <= y+yrad; ty++) {
  592.         for(tx = x-xrad; tx <= x+xrad; tx++) {
  593.           if(ty<0) continue;
  594.           if(ty>=p->height) continue;
  595.           if(tx<0) continue;
  596.           if(tx>=p->width) continue;
  597.       k = ty*rowstride + tx*3;
  598.           r += p->col[k+0];
  599.           g += p->col[k+1];
  600.           b += p->col[k+2];
  601.           n++;
  602.         }
  603.       }
  604.       k = y*rowstride + x*3;
  605.       tmp.col[k+0] = r / n;
  606.       tmp.col[k+1] = g / n;
  607.       tmp.col[k+2] = b / n;
  608.     }
  609.   }
  610.   killppm(p);
  611.   p->width = tmp.width;
  612.   p->height = tmp.height;
  613.   p->col = tmp.col;
  614. }
  615.  
  616. void putrgb_fast(struct ppm *s, float xo, float yo, guchar *d)
  617. {
  618.   guchar *tp;
  619.   tp = s->col + s->width * 3 * (int)(yo+0.5) + 3 * (int)(xo+0.5);
  620.   tp[0] = d[0];
  621.   tp[1] = d[1];
  622.   tp[2] = d[2];
  623. }
  624.  
  625. void putrgb(struct ppm *s, float xo, float yo, guchar *d)
  626. {
  627.   int x, y;
  628.   float aa, ab, ba, bb;
  629.   int k, rowstride = s->width * 3;
  630.  
  631.   x = xo;
  632.   y = yo;
  633.  
  634.   if((x < 0) || (y < 0) || (x >= s->width-1) || (y >= s->height-1))
  635.     return;
  636.  
  637.   xo -= x;
  638.   yo -= y;
  639.  
  640.   aa = (1.0-xo)*(1.0-yo);
  641.   ab = xo*(1.0-yo);
  642.   ba = (1.0-xo)*yo;
  643.   bb = xo*yo;
  644.  
  645.   k = y*rowstride + x*3;
  646.   s->col[k+0] *= (1.0-aa);
  647.   s->col[k+1] *= (1.0-aa);
  648.   s->col[k+2] *= (1.0-aa);
  649.   
  650.   s->col[k+3] *= (1.0-ab);
  651.   s->col[k+4] *= (1.0-ab);
  652.   s->col[k+5] *= (1.0-ab);
  653.  
  654.   s->col[k+rowstride+0] *= (1.0-ba);
  655.   s->col[k+rowstride+1] *= (1.0-ba);
  656.   s->col[k+rowstride+2] *= (1.0-ba);
  657.  
  658.   s->col[k+rowstride+3] *= (1.0-bb);
  659.   s->col[k+rowstride+4] *= (1.0-bb);
  660.   s->col[k+rowstride+5] *= (1.0-bb);
  661.  
  662.   s->col[k+0] += aa * d[0];
  663.   s->col[k+1] += aa * d[1];
  664.   s->col[k+2] += aa * d[2];
  665.   s->col[k+3] += ab * d[0];
  666.   s->col[k+4] += ab * d[1];
  667.   s->col[k+5] += ab * d[2];
  668.   s->col[k+rowstride+0] += ba * d[0];
  669.   s->col[k+rowstride+1] += ba * d[1];
  670.   s->col[k+rowstride+2] += ba * d[2];
  671.   s->col[k+rowstride+3] += bb * d[0];
  672.   s->col[k+rowstride+4] += bb * d[1];
  673.   s->col[k+rowstride+5] += bb * d[2];
  674. }
  675.  
  676. void drawline(struct ppm *p, float fx, float fy, float tx, float ty, guchar *col)
  677. {
  678.   float i;
  679.   float d, x, y;
  680.   if(fabs(fx-tx) > fabs(fy-ty)) {
  681.     if(fx > tx) { i=tx; tx=fx; fx=i; i=ty; ty=fy; fy=i; }
  682.     d = (ty-fy)/(tx-fx);
  683.     y = fy;
  684.     for(x = fx; x <= tx; x+=1.0) {
  685.       putrgb(p, x, y, col);
  686.       y += d;
  687.     }
  688.   } else {
  689.     if(fy > ty) { i=tx; tx=fx; fx=i; i=ty; ty=fy; fy=i; }
  690.     d = (tx-fx)/(ty-fy);
  691.     x = fx;
  692.     for(y = fy; y <= ty; y+=1.0) {
  693.       putrgb(p, x, y, col);
  694.       x += d;
  695.     }
  696.   }
  697. }
  698.